#include "base/DataRequest.h"
#include "mem/LineFlags.h"
#include "util/Logger.h"

NEW_DELETE_OPERATORS_CPP(DataRequest,1);

DataRequest::DataRequest (VA addr,
                          Processor* p,
                          Entity* source,
                          Entity* dest,
                          uint const dataSize_,
                          uint const headerSize)
    : MemoryRequest(addr, p, source, dest, dataSize_ + headerSize),
      dataSize(dataSize_),
      data((char*)CALLOC(dataSize_/WORD_SIZE, sizeof(uint))),
      exclusive(false),
      nonSpeculative(false),
      flushed(false),
      flags(NULL),
      mask(true)
{
}

DataRequest::~DataRequest () {
    FREE(data);

    if (flags != NULL) {
        delete flags;
    }
}

void DataRequest::insertData (const void* addr, uint size) {
    ASSERT(size <= dataSize);
    memcpy(data, addr, size);
}

void DataRequest::setWord (uint word) {
    ASSERT(dataSize >= sizeof(uint));
    *((uint*)data) = word;
}

void DataRequest::setWord (uint word, uint index) {
    ASSERT(WORD_SIZE == sizeof(uint));
    ASSERT(dataSize >= (index + 1) * sizeof(uint));
    ((uint*)data)[index] = word;
}

void DataRequest::setByte (uint8 byte) {
    *((uint8*)data) = byte;
}

void DataRequest::setByte (uint8 byte, uint index) {
    ASSERT(dataSize >= (index + 1));
    ((uint8*)data)[index] = byte;
}

uint DataRequest::getDataSize () const { 
    return dataSize; 
}

const char* DataRequest::getData () const { 
    return data; 
}

void DataRequest::setExclusive (bool a) {
    exclusive = a;
}

bool DataRequest::isExclusive () const {
    return exclusive;
}

bool DataRequest::isUncached () const {
    return uncached;
}

void DataRequest::setUncached (bool a) {
    uncached = a;
}

bool DataRequest::isNonSpeculative () const {
    return nonSpeculative;
}

LineMask const& DataRequest::getMask () const {
    return mask;
}

void DataRequest::setNonSpeculative (bool a) {
    nonSpeculative = a;
}

void DataRequest::setFlags (LineFlags* _flags) {
    flags = _flags;
}

LineFlags* DataRequest::getFlags () const {
    return flags;
}

void DataRequest::setFlushed (bool a) {
    flushed = a;
}

bool DataRequest::isFlushed () const {
    return flushed;
}

// NOTE: the following method is called when a request is resent after it got nacked with retry.
// make sure that all status newly added to the classes are properly reset in the method
void DataRequest::resetForRetry() {
    flags = NULL;
    flushed = false;    
    mask = LineMask::ALL_TRUE;
}

char const* DataRequest::toString () const {
    char tmp[512];
    strcpy(tmp, Request::toString());
    sim_sprintf((char*)string, "%s[%08llx]", tmp, getAddress());
    return string;
}
